package cs236369.webserver;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.message.BasicHttpResponse;

public class RequestHandler implements IRequestHandler  {

	private DefaultHttpServerConnection mConnToClient;
	private HttpRequest mRequest;
	private Map<String, String> mUrlParams;
	private String mPath;
	private IWebServerConfig mConfig;
	private Object mNotifier;
	
	public RequestHandler(SocketReader sr){
		mConnToClient = sr.getConnToClient();
		mRequest = sr.getHttpRequest();
		mUrlParams = sr.getUrlParams();
		mPath = sr.getPath();
		mConfig = sr.getConfig();
		mNotifier = sr.getNofier();
	}
	
	@Override
	public void run() {
		WebServerLog.log(this, "run() started");
		
		// notify that a task is out of the queue
		synchronized (mNotifier) {
			mNotifier.notifyAll();	
		}
		
		try{
		
			HttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), 200, "OK");
			setDedaultHeaders(response);
			File requestFile = new File(mPath);
			
			File tmpFile = requestFile;
			File serverDir = new File(mConfig.getBaseDirectory());
			while(tmpFile!=null && !tmpFile.equals(serverDir)){
				tmpFile = tmpFile.getParentFile();
			}
			
			if (tmpFile == null){ //the request is for a non permitted path
				ErrorHandler eh = new ErrorHandler();
				response.setStatusCode(403);
				response.setReasonPhrase("Forbidden");
				eh.handle(response, "The Path Of The File You Have " +
							"Requested Is Not Accesible By The Server",mConnToClient);
							
			}
			
			if (requestFile.isDirectory()){
				
				ErrorHandler eh = new ErrorHandler();
				response.setStatusCode(200);
				response.setReasonPhrase("OK");
				eh.handleDirectory(response, mPath, mConnToClient);
				return;
								
			}
			if (!requestFile.isFile()){
				ErrorHandler eh = new ErrorHandler();
				response.setStatusCode(404);
				response.setReasonPhrase("Not Found");
				eh.handle(response, "The File You Have Requested Was Not Found On The Server File:  " + requestFile.getAbsolutePath(),mConnToClient);
				return;
				
			}
			if (!requestFile.canRead()){
				ErrorHandler eh = new ErrorHandler();
				response.setStatusCode(403);
				response.setReasonPhrase("Forbidden");
				eh.handle(response, "The File You Have " +
							"Requested Is Not Accesible By The Server",mConnToClient);
				return;
			}
			
			
			int dotLocation = mPath.lastIndexOf('.');
			String fExt = mPath.substring(dotLocation+1);
			WebServerLog.log(this, "Requested file extensiom: " + fExt);
			
			ITypeHandler typeHandler = null;
			typeHandler = mConfig.getTypeHandlers().get(fExt);
			
			
			if (typeHandler == null){
				typeHandler = new DefaultTypeHandler(null); 
			}
					
	    				
			String mimeType = mConfig.getMimeMapping().get(fExt);
			if (mimeType != null){
				response.setHeader("Content-Type",mimeType);
			}

			typeHandler.init(mPath, mConnToClient, mUrlParams);
			typeHandler.handle(mRequest, response, null);
					
			
		} catch (Exception e) {
			System.err.println("ERROR: " + e.getMessage());
			e.printStackTrace();
			
			ErrorHandler eh = new ErrorHandler();

			HttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Server Error");
			RequestHandler.setDedaultHeaders(response);

			try {
				eh.handle(response, "Some Unexpected Internal Error Occured ", mConnToClient);
			} catch (HttpException e2) {
				System.err.println("ERROR: Cannot send error report to client " + e2.getMessage());
				e2.printStackTrace();
			} catch (IOException e2) {
				System.err.println("ERROR: Cannot send error report to client " + e2.getMessage());
				e2.printStackTrace();
			}

		}finally{
			WebServerLog.log(this, "run() ended");
			try {
				mConnToClient.shutdown();
			} catch (IOException e) {
				System.err.println("ERROR: Cannot shutdown connection" + e.getMessage());
				e.printStackTrace();
			}
					
		}
	}
	
	
	public static void setDedaultHeaders(HttpResponse response){
		
		SimpleDateFormat Date=new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z",new Locale("en","US"));
		Date.setTimeZone(TimeZone.getTimeZone("GMT"));
		response.setHeader("Date", Date.format(new java.util.Date()));
		response.setHeader("Connection","close");
		response.setHeader("Content-Type","text/html");
	}
}
